package org.sfnelson.sk.client.data;

import java.io.Serializable;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

@PersistenceCapable
public class User implements Serializable {

	private static final long serialVersionUID = 6912922614773343497L;

	@PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	Long id;
	
	@Persistent
	String name;
	
	@Persistent
	Long seed;
	
	public User(String name, long seed) {
		this.name = name;
		this.seed = seed;
	}
	
	public User() {}
	
	public Long getId() {
		return id;
	}
	
	public String getName() {
		return name;
	}
	
	public String toString() {
		return name;
	}
	
	/**
	 * Returns a random number between {@code 1} and {@code 100} (inclusive).
	 * This method will always return the same number for this user.
	 * 
	 * This method is intended for use in seeding a user's position in ranking
	 * algorithms.
	 */
	public int random() {
		return random(1, 100);
	}
	
	/**
	 * Returns a random number between {@code 1} and {@code max} (inclusive).
	 * This method will always return the same number for this user, given the
	 * same parameter.
	 * 
	 * This method is intended for use in seeding a user's position in ranking
	 * algorithms.
	 */
	public int random(int max) {
		return random(1, max);
	}

	/**
	 * Returns a random number between {@code min} and {@code max} (inclusive).
	 * This method will always return the same number for this user, given the
	 * same parameters.
	 * 
	 * This method is intended for use in seeding a user's position in ranking
	 * algorithms.
	 */
	public int random(int min, int max) {
		max = max + 1;
		Random r = new Random(seed);
		return min + r.nextInt(max - min);
	}
	
	private class Random {
		private long seed;
		
		public Random(long seed) {
			this.seed = seed;
		}
		
		public int nextInt(int n) {
			// Algorithm from java.util.Random
			if ((n & -n) == n) {
				return (int)((n * (long)next(31)) >> 31);
			}

			int bits, val;
			do {
				bits = next(31);
				val = bits % n;
			} while(bits - val + (n-1) < 0);
			return val;
		}

		private int next(int bits) {
			seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1);
			return (int)(seed >>> (48 - bits));
		}
	}
	
	public boolean equals(Object o) {
		if (o == this) {
			return true;
		}
		if (o instanceof User) {
			return name.equals(((User) o).name);
		} else {
			return false;
		}
	}
	
	public int hashCode() {
		return name.hashCode();
	}
}
